06 Docker部署AI Agent实战
本文把前面介绍的Docker核心概念和工具组合起来,完整演示一个Flask+Redis Agent服务的容器化部署。
示例项目是一个带访问计数的Agent API服务:Flask负责处理HTTP请求,Redis负责存储计数。功能较小,但流程完整,会用到Dockerfile编写、Compose编排、健康检查、数据持久化和开发热更新。
一、项目结构
agent-api/
├── src/
│ └── main.py # Flask应用
├── requirements.txt # Python依赖
├── Dockerfile # 镜像构建配置
├── .dockerignore # 构建排除文件
├── .env # 环境变量
├── compose.yaml # 服务编排
└── infra.yaml # 基础设施服务二、应用代码
python
# src/main.py
import os
import redis
from flask import Flask, request, jsonify
app = Flask(__name__)
cache = redis.Redis(
host=os.getenv("REDIS_HOST", "redis"),
port=int(os.getenv("REDIS_PORT", "6379")),
)
@app.route("/")
def index():
count = cache.incr("hits")
return jsonify({"message": "Agent服务运行中", "visits": count})
@app.route("/health")
def health():
try:
cache.ping()
return jsonify({"status": "healthy"}), 200
except redis.ConnectionError:
return jsonify({"status": "unhealthy"}), 500
@app.route("/chat", methods=["POST"])
def chat():
data = request.get_json()
user_message = data.get("message", "")
count = cache.incr("chat_count")
return jsonify({
"reply": f"收到你的第{count}条消息: {user_message}",
"count": count,
})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)text
# requirements.txt
flask
redis三、编写Dockerfile
dockerfile
FROM python:3.12-alpine
# 创建非root用户
RUN addgroup -S app && adduser -S app -G app
WORKDIR /app
# 先复制依赖文件,利用构建缓存
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
# 再复制源代码
COPY src ./src
# 设置环境变量
ENV PYTHONUNBUFFERED=1
# 切换到非root用户
USER app
EXPOSE 5000
CMD ["python", "src/main.py"]关键配置说明:
FROM python:3.12-alpine——用Alpine版本,镜像体积小- 创建非root用户——安全最佳实践
- 先COPY requirements.txt再COPY src——利用构建缓存,修改代码时不需要重装依赖
PYTHONUNBUFFERED=1——让Python直接输出日志,不缓冲USER app——以非root用户运行
四、编写.dockerignore
plaintext
.git
.env
__pycache__
*.pyc
.venv
*.md
docker-compose*.yaml
compose.yaml
infra.yaml
Dockerfile这些都是不需要打包进镜像的文件。尤其是.env,其中可能包含API Key;.git目录体积较大,对运行时也没有必要。
五、编写compose.yaml
yaml
include:
- path: ./infra.yaml
services:
web:
build: .
ports:
- "${APP_PORT}:5000"
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
depends_on:
redis:
condition: service_healthy
develop:
watch:
- action: sync+restart
path: ./src
target: /app/src
- action: rebuild
path: requirements.txtyaml
# infra.yaml
services:
redis:
image: redis:alpine
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
start_period: 10s
volumes:
redis-data:text
# .env
APP_PORT=8000
REDIS_HOST=redis
REDIS_PORT=6379配置项说明:
| 配置 | 作用 |
|---|---|
include: ./infra.yaml | 把基础设施服务拆到独立文件 |
build: . | 用当前目录的Dockerfile构建 |
ports: "${APP_PORT}:5000" | 端口映射,值从.env读取 |
depends_on + healthcheck | 等Redis就绪后再启动web |
develop.watch | 开发时代码热更新 |
volumes: redis-data | Redis数据持久化 |
六、运行和测试
6.1 首次启动
bash
docker compose up输出类似:
[+] Running 2/2
✔ Container agent-api-redis-1 Healthy 0.0s
✔ Container agent-api-web-1 Started 0.5sCompose会等Redis健康检查通过后,再启动web服务。
6.2 测试接口
bash
# 首页(带访问计数)
curl http://localhost:8000
# {"message":"Agent服务运行中","visits":1}
# 健康检查
curl http://localhost:8000/health
# {"status":"healthy"}
# Agent聊天接口
curl -X POST http://localhost:8000/chat \
-H "Content-Type: application/json" \
-d '{"message": "你好"}'
# {"count":1,"reply":"收到你的第1条消息: 你好"}6.3 验证数据持久化
bash
# 多访问几次,让计数增加
curl http://localhost:8000
curl http://localhost:8000
curl http://localhost:8000
# 停掉服务
docker compose down
# 重新启动
docker compose up -d
# 访问计数还在
curl http://localhost:8000
# {"message":"Agent服务运行中","visits":4}因为Redis数据保存在Volume里,docker compose down不会删除这份数据。
6.4 验证开发热更新
用docker compose up --watch启动:
bash
docker compose up --watch修改src/main.py里的返回消息:
python
return jsonify({"message": "Agent服务已更新", "visits": count})保存后,Compose会自动把变更同步到容器并重启。刷新页面即可看到新内容,不需要手动重建镜像。
七、查看日志和调试
bash
# 查看所有服务日志
docker compose logs -f
# 只看web服务日志
docker compose logs -f web
# 进入web容器
docker compose exec web sh
# 查看环境变量
docker compose exec web env | grep REDIS
# 测试web能否连通redis
docker compose exec web python -c "import redis; r = redis.Redis(host='redis'); print(r.ping())"
# 输出: True
# 查看redis里的数据
docker compose exec redis redis-cli GET hits八、生产部署建议
以上配置更偏开发环境。生产部署时,还需要补充以下配置:
8.1 关闭Debug模式
python
# 生产环境不要用debug=True
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)生产环境应使用Gunicorn代替Flask内置服务器:
dockerfile
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "src.main:app"]8.2 不暴露Redis端口
生产环境中,Redis通常不需要对外暴露端口,只需让web服务通过内部网络访问。
8.3 日志收集
yaml
services:
web:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"8.4 资源限制
yaml
services:
web:
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M九、总结
这个实战项目覆盖了Docker部署中最常见的流程:
| 步骤 | 用到的知识 |
|---|---|
| 编写Dockerfile | FROM、WORKDIR、COPY、RUN、ENV、USER、CMD |
| 构建缓存优化 | 先COPY依赖文件,再COPY源代码 |
| 安全最佳实践 | 非root用户、.dockerignore排除敏感文件 |
| Compose编排 | services、build、ports、environment |
| 服务依赖 | depends_on + healthcheck |
| 数据持久化 | Volume |
| 开发热更新 | Compose Watch |
| 环境管理 | .env文件 |
这个Docker系列到这里结束。从基础概念到Dockerfile编写,从镜像优化到Compose编排,再到网络、存储和实战部署,掌握这些内容后,就可以独立完成AI Agent服务的容器化部署。